/*******************************************************************************
 * Copyright (c) 2008 Sylvain Sicard.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the GNU Lesser Public License v2.1
 * which accompanies this distribution, and is available at
 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
 * 
 * Contributors:
 *     Noel De Palma - initial API and implementation
 ******************************************************************************/
package fr.jade.service.application.deployer;

import java.util.HashMap;
import java.util.Map;

import org.objectweb.fractal.adl.implementations.ImplementationBuilder;
import org.objectweb.fractal.api.Component;
import org.objectweb.fractal.api.NoSuchInterfaceException;
import org.objectweb.fractal.api.Type;
import org.objectweb.fractal.api.control.BindingController;
import org.objectweb.fractal.api.control.IllegalBindingException;
import org.objectweb.fractal.api.control.IllegalLifeCycleException;
import org.objectweb.fractal.api.factory.GenericFactory;
import org.objectweb.fractal.api.factory.InstantiationException;
import org.objectweb.fractal.util.Fractal;

import fr.jade.base.JadeBaseComponent;
import fr.jade.service.nodes.allocator.Allocator;
import fr.jade.util.FractalUtil;

/**
 * This builder is used to create component of the application.
 * If a component have a virtual node :
 * 		if a physical node is already allocated for this virtual node :
 * 			 the component is deployed on this node.
 *      else a new physical node is allocated for the virtual node
 * 			 the component is deployed on this node.
 * Else the component is deployed locally. 
 * This builder use an allocator to allocate generic factory.
 * Component are created remotly 
 * @author Noel De Palma
 * @contact noel.depalma@inrialpes.fr
 */
public class ApplicationImplementationBuilder extends JadeBaseComponent implements BindingController,
    ImplementationBuilder {

  /**
   * the node allocator.
   */
  private final static String allocatorItfName = "allocator";
  private Allocator  allocator;

  /**
   * map to store allocated node.
   * in this version the node namespace is shared beetwen multiple application.
   * this must be an option of the adl deployer.
   * the adl deployer must provide a reset method to flush the nodecontext.
   */
  private static Map<String, GenericFactory> nodecontext = new HashMap<String, GenericFactory>();

  @SuppressWarnings("unchecked")
  public Object createComponent(final Object type, final String name, final String definition,
                                final Object controllerDesc, final Object contentDesc, final Object context) throws Exception {
    
    log("createComponent(" + name + ", " + definition + ", " + (String) contentDesc + ", " + (String) controllerDesc + ")");

    String nd = (String) (((Map<String, Object>) context).get("physicalNode"));
    if (nd == null)
      throw new InstantiationException("no bootstrap component found to create " + name);
    
    GenericFactory node1 = nodecontext.get(nd);
    if (node1 == null) {
      node1 = FractalUtil.getGenericFactory(allocator.alloc(nd));
      nodecontext.put(nd, node1);
    }
    Component res = node1.newFcInstance((Type) type, controllerDesc, contentDesc);

    try {
      Fractal.getNameController(res).setFcName(name);
    } catch (NoSuchInterfaceException ignored) { }

    return res;

  }

  public String[] listFc() {
    String[] listItf = new String[] { allocatorItfName };
    return super.concat(listItf, super.listFc());
  }

  public Object lookupFc(final String cItf) throws NoSuchInterfaceException {
    if (cItf.equals(allocatorItfName)) {
      return allocator;
    }
    return super.lookupFc(cItf);
  }

  public void bindFc(final String cItf, final Object sItf) throws NoSuchInterfaceException, IllegalBindingException, IllegalLifeCycleException {
    if (cItf.equals(allocatorItfName))
      allocator = (Allocator) sItf;
    else
      super.bindFc(cItf, sItf);
  }

  public void unbindFc(final String cItf) throws NoSuchInterfaceException, IllegalBindingException, IllegalLifeCycleException {
    if (cItf.equals(allocatorItfName)) 
      allocator = null;
    else
      super.unbindFc(cItf);
  }

}
